#include "RpcChannel.h"
#include "myrpc.pb.h"
#include "../myrpccontroller.h"


namespace myrpc
{
	
	bool RpcChannel::RegisterService(::google::protobuf::Service * service)
	{	
		const google::protobuf::ServiceDescriptor *serviceDesc = service->GetDescriptor();
		const google::protobuf::MethodDescriptor  *methodDesc = NULL;
		const google::protobuf::Message           *request = NULL;
		const google::protobuf::Message           *response = NULL;
	
		for (int i = 0; i < serviceDesc->method_count(); ++i) {
			methodDesc = serviceDesc->method(i);
			request = &service->GetRequestPrototype(methodDesc);
			response = &service->GetResponsePrototype(methodDesc);
			addMethod(MethodDes(methodDesc, request, response), methodDesc->name());
		}

		_service = service;
		return false;
	}
	
	bool RpcChannel::Start(std::string ip, int port)
	{	
		server.Init();
		server.SetConnectReach([=](std::shared_ptr<myrpc::mynet::Session> session)
		{	
			InitSession(session);
			_sessions.push_back(session);
		});
		server.Listen(ip, port);
		return false;
	}
	
	bool RpcChannel::DoRpc(mynet::PackagePtr pack)
	{	

		myrpc::Request body = pack->body;
		body.id();
	
		MethodDes methon = _methods[body.method()];
		google::protobuf::Message* req = methon.request->New();
		req->ParseFromString(body.data());
		google::protobuf::Message* resp = methon.response->New();
		
		_service->CallMethod(methon.descriptor , new MyRpcController , req , resp , NULL);

		myrpc::Response response;
		std::string r;
		response.set_id(body.id());
		response.set_data(resp->SerializeAsString());
		myrpc::Header header;
		std::string sbody = response.SerializeAsString();
		header.set_len(sbody.size());
		std::string buf = header.SerializeAsString();
		response.AppendToString(&buf);
		pack->tcphandlePtr->Send(buf , buf.size());
		return false;
	}

	void RpcChannel::InitSession(const std::shared_ptr<myrpc::mynet::Session>& session)
	{
		session->SetOnRead([=](myrpc::mynet::PackagePtr package) {
			DoRpc(package);
		});
	}
 
}
